using System;
using System.Collections.Generic;
using System.Linq;
using DataObject.Core;
using DataObject.Database;

namespace DataObject.DataAccess
{
    public class CabinStatusDAO : DataBaseProcessBase<CabinStatusEntity, OBSDataContext>
    {
        #region CreateInstant

        public static CabinStatusDAO CreateInstant()
        {
            return new CabinStatusDAO();
        }

        #endregion

        public List<CabinStatusEntity> GetAllCabinStatus()
        {
            using (var db = new OBSDataContext(connectionString))
            {
                return db.CabinStatusEntities.ToList();
            }
        }

        public IList<CabinStatus> FindCabinStatus(IList<string> boatIds, DateTime? fromDate, DateTime? toDate,
            bool isShowAll) //, int? page, int? row, out int count, HashSet<string> sortClause)
        {
            using (var db = new OBSDataContext(connectionString))
            {
                IQueryable<CabinStatusEntity> query = (from table in db.CabinStatusEntities select table);

                IQueryable<CabinStatus> query1;
                if (isShowAll)
                {
                    query1 = from cabin in db.CabinEntities
                        join cabinstatus in
                            (
                                from i in query
                                where ((fromDate.HasValue && i.Date >= fromDate.Value.Date) || !fromDate.HasValue)
                                      && ((toDate.HasValue && i.Date <= toDate.Value.Date) || !toDate.HasValue)
                                      && (i.ReservationDetail != null
                                          && i.ReservationDetail.Reservation != null
                                          && i.ReservationDetail.Reservation.Status != 1)
                                select i)
                            on cabin.CabinID equals cabinstatus.CabinID
                            into cs
                        from c in cs.DefaultIfEmpty()
                        select new CabinStatus
                        {
                            BoatID = cabin.BoatID,
                            BoatColor = cabin.BoatEntity.Color,
                            CabinID = cabin.CabinID,
                            CabinNumber = cabin.CabinNumber,
                            DepartureDate = (null == c ? DateTime.Now : c.Date),
                            Booking =
                                MapBooking(c.ReservationDetail.Reservation, null == c ? 0 : c.Status,
                                    (c == null ? DateTime.Now : c.Date)),
                            Status = null == c ? 0 : c.Status
                        };
                }
                else
                {
                    query1 = from cabin in db.CabinEntities
                        join cabinstatus in query
                            on cabin.CabinID equals cabinstatus.CabinID
                        where ((fromDate.HasValue && cabinstatus.Date >= fromDate.Value.Date) || !fromDate.HasValue)
                              && ((toDate.HasValue && cabinstatus.Date <= toDate.Value.Date) || !toDate.HasValue)
                              && (cabinstatus.ReservationDetail != null
                                  && cabinstatus.ReservationDetail.Reservation != null
                                  && cabinstatus.ReservationDetail.Reservation.Status != 1)
                        select new CabinStatus
                        {
                            BoatID = cabin.BoatID,
                            BoatColor = cabin.BoatEntity.Color,
                            CabinID = cabin.CabinID,
                            CabinNumber = cabin.CabinNumber,
                            DepartureDate = cabinstatus.Date,
                            Booking =
                                MapBooking(cabinstatus.ReservationDetail.Reservation, cabinstatus.Status,
                                    cabinstatus.Date),
                            Status = cabinstatus.Status,
                        };
                }

                IList<CabinStatus> models;
                if (boatIds.Count > 0)
                {
                    IEnumerable<CabinStatus> query2 = from m in query1.ToList()
                        where boatIds.Contains(m.BoatID)
                        select m;
                    models = query2.ToList();
                }
                else
                {
                    IEnumerable<CabinStatus> query2 = from m in query1.ToList()
                                                      where m.BoatID == "TJ"
                                                      select m;
                    models = query2.ToList();
                }
                return models;
            }
        }

        public List<CabinStatusEntity> FindCabinStatus(int? cabinID, DateTime? date, int? status,
            HashSet<string> sortClause)
        {
            int count;
            return FindCabinStatus(cabinID, date, status, null, null, out count, sortClause);
        }

        public List<CabinStatusEntity> FindCabinStatus(int? cabinID, DateTime? date, int? status, int? page, int? row,
            out int count, HashSet<string> sortClause)
        {
            using (var db = new OBSDataContext(connectionString))
            {
                IQueryable<CabinStatusEntity> query = (from table in db.CabinStatusEntities select table);
                if (cabinID.HasValue)
                    query = query.Where(table => table.CabinID == cabinID.Value);
                if (date.HasValue)
                    query = query.Where(table => table.Date == date.Value.Date);
                if (status.HasValue)
                    query = query.Where(table => table.Status == status.Value);
                for (int i = sortClause.Count - 1; i >= 0; i--)
                    query = query.OrderBy(sortClause.ElementAt(i));
                count = query.Count();
                if (page.HasValue && row.HasValue)
                    return query.PageIQuery(page.Value, row.Value).ToList();
                return query.ToList();
            }
        }

        public CabinStatusEntity GetCabinStatus(Guid pRdid, int pCabinID, DateTime pDate)
        {
            using (var db = new OBSDataContext(connectionString))
            {
                return
                    db.CabinStatusEntities.SingleOrDefault(
                        a => a.CabinID == pCabinID && a.Date.Date == pDate.Date && a.RDID == pRdid);
            }
        }

        public void InsertCabinStatuses(List<CabinStatusEntity> cabinStatuses)
        {
            using (var db = new OBSDataContext(connectionString))
            {
                db.CabinStatusEntities.InsertAllOnSubmit(cabinStatuses);
                db.SubmitChanges();
            }
        }

        public void UpdateCabinStatus(CabinStatusEntity item)
        {
            using (var db = new OBSDataContext(connectionString))
            {
                db.UpdateCabinStatus(item.RDID, item.CabinID, item.Date, item.Status, item.BlockDates);
            }
        }

        private string GetCssClass(int status, bool isCharter, string boat, int nights = 1)
        {
            string cssClass = define.CssNormal;

            if (isCharter)
            {
                cssClass = define.CssCharter;
            }
            else
            {
                switch (status)
                {
                    case 1:
                        // Booked
                        if (boat == "TJ")
                        {
                            cssClass = nights == 2 ? define.CssBooked2 : define.CssBooked;
                        }
                        else
                        {
                            cssClass = nights == 2 ? define.CssBooked2Boat2 : define.CssBookedBoat2;
                        }
                        break;
                    case 2:
                        // Blocked
                        cssClass = define.CssBlocked;
                        break;
                    //default:
                    //    // Normal - Hidden
                    //    break;
                }
            }

            return cssClass;
        }

        private BookingClass MapBooking(Reservation entity, int status, DateTime currentDate)
        {
            var booking = new BookingClass();
            if (entity != null)
            {
                booking.AgentID = entity.GuestID.ToUpper();
                booking.ReservationID = entity.ReservationID;
                booking.BookingCode = entity.ReservationCode;
                booking.DepartureDate = entity.CheckInDate;
                booking.IsShuttle = entity.IsShuttle;
                booking.HotelAddress = entity.HotelAddress;
                booking.Note = entity.Note;
                booking.Pickup = entity.Pickup;
                booking.RouteName = entity.RouteNumber +
                                    (entity.SubRouteCode == null ? String.Empty : ("-" + entity.SubRouteCode));
                booking.SubRouteCode = entity.SubRouteCode;
                booking.NumOfCabins = entity.NumOfCabins;
                booking.NumOfNights = entity.NumOfNights;
                booking.NumOfPax = entity.NumOfPax;
                booking.Status = entity.Status;
                booking.CreateByID = entity.CreatedByID;
                booking.CreationDate = entity.CreationDate;
                booking.ModifiedByID = entity.ModifiedByID;
                booking.ModifiedDate = entity.ModifiedDate;
                booking.CssClass = GetCssClass(status, entity.IsCharter, entity.BoatID, booking.NumOfNights);
                booking.CurrentDate = currentDate;

                IList<string> cabin = new List<string>();
                int doubleBed = entity.ReservationDetails.Count(x => x.Status == 1);
                int twinBed = entity.ReservationDetails.Count(x => x.Status == 2);
                int singleBed = entity.ReservationDetails.Count(x => x.Status == 3);
                if (doubleBed > 0) cabin.Add(String.Format("{0:00} Double(s)", doubleBed));
                if (twinBed > 0) cabin.Add(String.Format("{0:00} Twin(s)", twinBed));
                if (singleBed > 0) cabin.Add(String.Format("{0:00} Single(s)", singleBed));

                booking.CabinTypes = String.Join(", ", cabin.ToArray());
            }

            return booking;
        }

    }
}